
#ifndef WORLD_H_
#define WORLD_H_

#include "Core.h"
#include "Aabb2.h"
#include "ConstraintSolver.h"
#include "ContactSolver.h"
#include "Collider.h"
#include "SingleSweepAndPrune.h"
#include "VelocityChange.h"

#define PIXCLIP_BORDER				20

namespace p2 {

class World: public RealTimeType, public BroadPhaseObserver
{
DECLARE_RTT(World, RealTimeType);

public:
	inline World(Aabb2<real> const& worldExtent);
	virtual ~World();

	inline void setG(Vector2<real> g);
	inline Vector2<real> getG();
	inline real getRestingContactThreshold();

	inline void attach(Entity* element);
	inline void detach(Entity* element);
	inline void attach(Constraint* constraint);
    inline void detach(Constraint* constraint);

	void integrate(real64 th);
    Element* elementContains(Vector2<real> p);

	/*
	 * p2BroadPhaseObserver
	 */
	bool addPair(void* data0, void* data1);
	bool removePair(void* data0, void* data1);

	boost::shared_ptr<BroadPhase>& getBroadPhase()
	{
		return _broadPhase;
	}

	Collider& getCollider()
	{
		return _collider;
	}

	Constraint::Set const& getConstraints() const
	{
		return _constraints;
	}

	Entity::Set const& getEntities() const
	{
		return _entities;
	}

	real64 getTimeMultiplier() const
	{
		return _timeMultiplier;
	}

	void setTimeMultiplier(real64 timeMultiplier)
	{
		_timeMultiplier = timeMultiplier;
	}

	Aabb2<real> const& getClipBound() const
	{
		return _clipBound;
	}

	void setClipBound(const Aabb2<real>& clipBound)
	{
		_clipBound = clipBound;
	}

	Aabb2<real> const& getWorldBound() const
	{
		return _worldBound;
	}

	void setWorldBound(const Aabb2<real>& worldBound)
	{
		_worldBound = worldBound;
	}

	real64 getTimeStep() const
	{
		return _dTu;
	}

	void setTimeStep(real64 dtu)
	{
		_dTu = dtu;
	}

private:
	Aabb2<real> _worldBound, _clipBound;

	Entity::Set _entities;
	Constraint::Set _constraints;

	Vector2<real> _g;
	real _restingContactThreshold;

	real64 _dTu;
	real64 _t0;
	real64 _accumulatedT;
    real64 _timeMultiplier;

	boost::shared_ptr<BroadPhase> _broadPhase;
	ContactSolver _contactSolver;
	ConstraintSolver _constraintSolver;
	Collider _collider;
};

#if _MSC_VER
#	pragma warning( push )
#	pragma warning( disable: 4355 )
#endif
inline World::World(Aabb2<real> const& worldBound)
	:   _worldBound(worldBound), _clipBound(worldBound),
	    _entities(), _constraints(),
		_g(Vector2<real>::ZERO), _restingContactThreshold(0.f),
		_dTu(0.02),
        _t0(0),
        _accumulatedT(0),
        _timeMultiplier(1),
        _broadPhase(new SingleSweepAndPrune),
        _contactSolver(this),
        _constraintSolver(this),
        _collider()
{
	_broadPhase->setObserver(this);

	Vector2<real> pixClipBorder(+PIXCLIP_BORDER, +PIXCLIP_BORDER);
	_clipBound.min() += pixClipBorder;
	_clipBound.max() -= pixClipBorder;
}
#if _MSC_VER
#	pragma warning( pop )
#endif

inline void World::setG(Vector2<real> g)
{
	_g = g;
	real glen = Vector2<real>::length(_g);
	_restingContactThreshold = Math<real>::Sqrt(2.f * glen * 5.f);
}

inline Vector2<real> World::getG()
{
	return _g;
}

inline real World::getRestingContactThreshold()
{
	return _restingContactThreshold;
}

inline void World::attach(Entity* entity)
{
	entity->setOwner(this);
	_entities.insert(entity);
}

inline void World::detach(Entity* entity)
{
    _entities.erase(entity);
}

inline void World::attach(Constraint* constraint)
{
	constraint->setOwner(this);
	_constraints.insert(constraint);
}
    
inline void World::detach(Constraint* constraint)
{
    _constraints.erase(constraint);
}

}

#endif	//WORLD_H_
